from sqlalchemy.orm import Session
from typing import List, Optional, Union
from datetime import datetime
from app.repositories.config_repository import ConfigRepository
from app.repositories.scan_repository import ScanResultRepository
from app.repositories.scan_path_repository import ScanPathRepository
import app.schemas as schemas
from app.clients.qbittorrent import QBittorrentClient
from app.clients.transmission import TransmissionClient
from app.scanner import FileScanner
import logging
import os
from typing import Dict, Any

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

class TorrentService:
    def __init__(self, db: Session):
        self.db = db
        self.config_repo = ConfigRepository()
        self.scan_repo = ScanResultRepository()
        self.scan_path_repo = ScanPathRepository()
        self.file_scanner = FileScanner()
        self.db_path = self.db.database_path

    async def add_client_config(self, config: schemas.ConfigCreate) -> schemas.Config:
        return await self.config_repo.create_config(self.db, config)

    async def get_client_configs(self) -> List[schemas.Config]:
        return await self.config_repo.get_configs(self.db)

    async def update_client_config(self, config_id: int, config: schemas.ConfigCreate) -> Optional[schemas.Config]:
        return await self.config_repo.update_config(self.db, config_id, config)

    async def delete_client_config(self, config_id: int) -> bool:
        return await self.config_repo.delete_config(self.db, config_id)

    async def test_client_connection(self, config: schemas.ConfigCreate) -> bool:
        client = self._create_client(config)
        if client:
            return await client.test_connection()
        return False

    async def scan_files(self, config_id: Optional[int] = None) -> List[schemas.ScanResult]:
        # 获取所有启用的扫描路径
        scan_paths = await self.scan_path_repo.get_enabled_paths(self.db)
        if not scan_paths:
            raise ValueError("没有配置扫描路径")

        # 如果指定了配置ID,只使用该配置
        if config_id is not None:
            config = await self.config_repo.get_config(self.db, config_id)
            if not config:
                raise ValueError("配置不存在")
            if not config.get_enabled():
                raise ValueError("该下载器已禁用")
            configs = [config]
        else:
            # 否则使用所有启用的配置
            configs = await self.config_repo.get_enabled_configs(self.db)
            if not configs:
                raise ValueError("没有启用的下载器")

        all_not_seeding_files = []
        all_seeding_files = []

        # 从所有下载器获取做种文件
        logger.info("===== 开始获取远程做种文件 =====")
        for config in configs:
            client = self._create_client(config)
            if not client:
                continue
            if not await client.test_connection():
                continue
            seeding_files = await client.get_seeding_files()
            logger.info(f"从 {config.client_type}:{config.host} 获取到 {len(seeding_files)} 个做种文件")
            all_seeding_files.extend(seeding_files)

        # 记录所有做种文件的详细信息
        logger.info("===== 所有远程做种文件详细信息 =====")
        for idx, file in enumerate(all_seeding_files):
            logger.info(f"做种文件 {idx+1}: {file}")

        # 扫描所有配置的路径
        logger.info("===== 开始扫描本地文件 =====")
        for scan_path in scan_paths:
            path = scan_path.get_path()
            logger.info(f"扫描路径: {path}")
            local_files = await self.file_scanner.scan_directory(path)
            logger.info(f"在路径 {path} 中找到 {len(local_files)} 个文件")
            
            # 提取做种文件的路径列表
            seeding_paths = [file["path"] for file in all_seeding_files]
            logger.info("===== 开始比较本地文件和远程做种文件 =====")
            not_seeding = await self.file_scanner.compare_files(local_files, seeding_paths)
            logger.info(f"在路径 {path} 中找到 {len(not_seeding)} 个未做种文件")
            all_not_seeding_files.extend(not_seeding)

        # 保存扫描结果到数据库
        scan_results = [
            schemas.ScanResultCreate(
                file_path=file["path"],
                file_name=file["name"],
                file_size=file["size"],
                status="not_seeding"
            )
            for file in all_not_seeding_files
        ]
        
        # 清除旧的扫描结果
        await self.scan_repo.delete_all_results(self.db)
        
        # 创建新的扫描结果
        results = await self.scan_repo.create_scan_results(self.db, scan_results)
        logger.info(f"扫描完成，共找到 {len(results)} 个未做种文件")
        
        return results

    def _create_client(self, config: Union[schemas.Config, schemas.ConfigCreate]):
        if config.client_type.lower() == "qb":
            return QBittorrentClient(
                host=config.host,
                port=config.port,
                username=config.username,
                password=config.password
            )
        elif config.client_type.lower() == "transmission":
            return TransmissionClient(
                host=config.host,
                port=config.port,
                username=config.username,
                password=config.password
            )
        return None

    async def get_scan_results(self, status: Optional[str] = None, skip: int = 0, limit: int = 100) -> List[schemas.ScanResult]:
        results = await self.scan_repo.get_scan_results(self.db, skip=skip, limit=limit, status=status)
        return [schemas.ScanResult.from_orm(r) for r in results]

    async def get_scan_result(self, result_id: int) -> Optional[schemas.ScanResult]:
        result = await self.scan_repo.get_scan_result(self.db, result_id)
        return schemas.ScanResult.from_orm(result) if result else None

    async def update_scan_result_status(self, result_id: int, status: str) -> Optional[schemas.ScanResult]:
        result = await self.scan_repo.update_scan_result_status(
            self.db, 
            result_id, 
            status,
            action_time=datetime.utcnow()
        )
        return schemas.ScanResult.from_orm(result) if result else None

    async def start_scan(self):
        """开始扫描"""
        try:
            logger.info("开始全局扫描...")
            
            # 获取所有启用的扫描路径
            scan_paths = await self.scan_path_repo.get_enabled_paths(self.db)
            logger.info(f"找到 {len(scan_paths)} 个扫描路径")

            # 收集所有做种文件
            seeding_files = []
            enabled_configs = await self.config_repo.get_enabled_configs(self.db)
            logger.info(f"找到 {len(enabled_configs)} 个启用的下载器")
            
            for config in enabled_configs:
                try:
                    client = self._get_client(config)
                    files = await client.get_seeding_files()
                    logger.info(f"从下载器 {config.client_type}:{config.host} 获取到 {len(files)} 个做种文件")
                    seeding_files.extend(files)
                except Exception as e:
                    logger.error(f"从下载器 {config.client_type}:{config.host} 获取文件失败: {str(e)}")
                    raise Exception(f"从下载器获取文件失败: {str(e)}")

            # 扫描本地文件
            local_files = []
            for path in scan_paths:
                try:
                    files = self._scan_directory(path.path)
                    logger.info(f"从路径 {path.path} 扫描到 {len(files)} 个文件")
                    local_files.extend(files)
                except Exception as e:
                    logger.error(f"扫描目录 {path.path} 失败: {str(e)}")
                    raise Exception(f"扫描目录失败: {str(e)}")

            # 对比文件
            not_seeding = self._compare_files(local_files, seeding_files)
            logger.info(f"找到 {len(not_seeding)} 个未做种文件")

            # 保存结果
            await self._save_results(not_seeding)
            
            return {"status": "completed", "not_seeding_count": len(not_seeding)}
            
        except Exception as e:
            logger.error(f"扫描过程出错: {str(e)}")
            raise HTTPException(status_code=500, detail=str(e))
            
    def _compare_files(self, local_files: List[str], seeding_files: List[Dict[str, Any]]) -> List[str]:
        """对比本地文件和做种文件"""
        logger.info("开始对比文件...")
        
        # 提取做种文件的路径列表
        seeding_paths = [file["path"] for file in seeding_files]
        
        # 标准化路径
        local_files = [os.path.normpath(f) for f in local_files]
        seeding_paths = [os.path.normpath(f) for f in seeding_paths]
        
        # 对比文件
        not_seeding = []
        for local_file in local_files:
            if local_file not in seeding_paths:
                logger.info(f"发现未做种文件: {local_file}")
                not_seeding.append(local_file)
        
        return not_seeding
